package com.mach.platform.service;

import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import com.mach.platform.constants.CommonConstants;
import com.mach.platform.domain.EnergyMenu;
import com.mach.platform.domain.EnergyStruc;
import com.mach.platform.repository.EnergyStrucRepo;
import com.mach.platform.service.js.iot.IOTJsService;
import com.mach.platform.service.js.iot.IOTVirDevService;
import com.mach.platform.utils.RecurFactory;
import com.mach.platform.utils.springdata.DynamicSpecifications;
import com.mach.platform.utils.springdata.SearchFilter;
import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.transaction.Transactional;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Administrator
 * @Description:
 * @Package: com.mach.platform.service
 * @time 2018/10/19 0019 14:32
 */
@Service
public class EnergyStrucServiceImpl implements BaseService<EnergyStruc> {

    @Autowired
    private EnergyStrucRepo energyStrucRepo;

    @PersistenceContext
    private EntityManager em;

    @Autowired
    IOTJsService iotJsService;

    /**
     * 保存
     *
     * @param energyStruc 保存的实体
     * @return T 返回保存后的实体
     */
    @Transactional(rollbackOn = Exception.class)
    @Override
    public EnergyStruc save(EnergyStruc energyStruc) {
        return energyStrucRepo.saveAndFlush(energyStruc);
    }

    /**
     * 插入，批量保存
     *
     * @param list 实体集合
     * @return List<T>
     */
    @Override
    public List<EnergyStruc> insertObjInBatch(List<EnergyStruc> list) {
        return null;
    }

    /**
     * 更新
     *
     * @param energyStruc 跟新的实体
     * @return T
     */
    @Transactional(rollbackOn = Exception.class)
    @Override
    public EnergyStruc update(EnergyStruc energyStruc) {
        return energyStrucRepo.saveAndFlush(energyStruc);
    }

    /**
     * 删除--批量删除
     *
     * @param ids 批量删除id
     * @return int 影响数
     */
    @Transactional(rollbackOn = Exception.class)
    @Override
    public int delete(Long[] ids) {

        int falg = 0;

        for (int i = 0; i < ids.length; i++) {
            // 获取 该节点下的子级空间id--- 包含自己
            String sql = "select countupEnergySpaceSons (" + ids[i] + ")";
            String singleResult = em.createNativeQuery(sql).getSingleResult().toString();
            List<Long> sonIds = Splitter.on(",").splitToList(singleResult).stream().filter(str -> !str.equals(""))
                    .map(si -> Long.parseLong(si)).collect(Collectors.toList());
            energyStrucRepo.deleteByIdIn(sonIds.stream().toArray(Long[]::new));
            falg += sonIds.size();
        }

        return falg;
    }

    /**
     * 获取列表数据---使用 com.mach.platform.utils.springdata  下的DynamicSpecifications 的
     * 写法进行分页查询
     *
     * @param pageable 分页参数
     * @param params   其他参数
     * @return Page<T>
     */
    @Override
    public Page<EnergyStruc> list(Pageable pageable, Map params) {
        Specification condications = DynamicSpecifications
                .bySearchFilter(SearchFilter.parse(params).values(), EnergyStruc.class);
        return energyStrucRepo.findAll(condications, pageable);
    }

    /**
     * 获取单体 数据
     *
     * @param id 获取详情的id
     * @return T
     */
    @Override
    public EnergyStruc info(Long id) {
        return null;
    }

    /**
     * 获取递归树形数据
     *
     * @param factory
     * @param type
     * @return
     */
    public List<EnergyStruc> getTreeDatas(String factory, String type) {

        List<EnergyStruc> dbResult = energyStrucRepo.findAllByType(type);
        List<EnergyStruc> result = new ArrayList<>();

        // 树节点展开只显示到车间级
        if (dbResult.size() > 0) {
            dbResult.forEach(item -> {
                int level = item.getLevel() != null ? item.getLevel() : -1;
                if (level != -1 && level < 2) {
                    item.setExpand(true);
                }
            });
        }

        if (dbResult.size() > 0) {
            EnergyStruc father = dbResult.stream().filter(item -> item.getPid().equals(0L)).findFirst().get();
            result.add(new RecurFactory<EnergyStruc>() {
                @Override
                public boolean finish(EnergyStruc son, EnergyStruc father) {
                    return son.getPid().equals(father.getId());
                }

                @Override
                public void handleChildren(List<EnergyStruc> t, EnergyStruc father) {
                    father.setChildren(t);
                }

                @Override
                public Comparator<EnergyStruc> sortMethod() {
                    return Comparator.comparingInt(EnergyStruc::getSort);
                }
            }.build(dbResult, father));
        }

        return result;
    }


    /**
     * 获取递归树形数据
     *
     * @param type
     * @return
     */
    public List<EnergyStruc> loadModelSpaceDatas(String type) {

        List<EnergyStruc> dbResult = energyStrucRepo.findAllByType(type);
        List<EnergyStruc> result = new ArrayList<>();

        // 树节点展开只显示到车间级
        if (dbResult.size() > 0) {
            dbResult.forEach(item -> {
                int level = item.getLevel() != null ? item.getLevel() : -1;
                if (level != -1 && level < 2) {
                    item.setExpand(true);
                }
            });
        }

        if (dbResult.size() > 0) {
            EnergyStruc father = dbResult.stream().filter(item -> item.getPid().equals(0L)).findFirst().get();
            result.add(new RecurFactory<EnergyStruc>() {
                @Override
                public boolean finish(EnergyStruc son, EnergyStruc father) {
                    return son.getPid().equals(father.getId());
                }

                @Override
                public void handleChildren(List<EnergyStruc> t, EnergyStruc father) {
                    father.setChildren(t);
                }

                @Override
                public Comparator<EnergyStruc> sortMethod() {
                    return Comparator.comparingInt(EnergyStruc::getSort);
                }
            }.build(dbResult, father));
        }

        return result;
    }

    /**
     * 判断是否有菜单
     *
     * @param space
     * @return
     */
    public List<Map> loadEnergyStuctsMenus(String space) {

        List<String> levels = Splitter.on("/").splitToList(space);
        String sql = "";
        if (levels.size() == 1) {
            sql = "select distinct type from energy_struc where type is not null";
        }
        if (levels.size() == 2) {
            sql = "select * from energy_struc where name = '" + levels.get(1) + "'";
        }
        if (levels.size() == 3) {
            sql = "select one.*\n" +
                    "from energy_struc one\n" +
                    "         left join energy_struc two on two.id = one.pid\n" +
                    "where 1=1\n" +
                    " and two.name = '" + levels.get(1) + "' and one.name = '" + levels.get(2) + "'";
        }

        List<String> orderNames = Stream.of("总览", "碳排", "成本", "水", "电", "燃气", "蒸汽", "冷量", "压缩空气").collect(Collectors.toList());
        Ordering ordering = Ordering.explicit(orderNames);
        Query nativeQuery = em.createNativeQuery(sql);
        nativeQuery.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        List<Map> dbResult = nativeQuery.getResultList();
        dbResult = dbResult.stream().filter(it -> !"模板".equals(it.get("type").toString()) && !"中水".equals(it.get("type").toString())).map(m -> {
            m.put("isMouse", false);
            String type = CommonConstants.EMNUS.get(m.get("type").toString());
            m.put("name", type);
            m.put("icon", type);
            m.put("title", m.get("type"));
            if (!"总览".equals(type)) {
                m.put("path", "/console/" + type);
            } else {
                m.put("path", "/console");
            }

            return m;
        }).sorted((o1, o2) -> {
            // 排序
            if (orderNames.contains(o1.get("type").toString()) && orderNames.contains(o1.get("type").toString())) {
                return ordering.nullsFirst().compare(o1.get("type").toString(), o2.get("type").toString());
            } else {
                return 0;
            }
        }).collect(Collectors.toList());


        return dbResult;

    }

    public List<EnergyStruc> loadWorkshopEnergyStuctsMenus(String type, String spaces) {

        List<EnergyStruc> result;
        String enType = CommonConstants.EMNUS.get(type);
        List<EnergyStruc> energyStrucs = loadModelSpaceDatas(enType);

        Object energySpaceId = iotJsService.getEnergySpaceId(spaces, type);

        Long parseInt = Long.parseLong(energySpaceId.toString());

        if (parseInt != -1) {

            class Inner {

                List<EnergyStruc> callback = null;

                public void recurison(List<EnergyStruc> lists) {
                    for (EnergyStruc es : lists) {
                        if (es.getId().equals(parseInt)) {
                            callback = es.getChildren();
                        } else {
                            if (es.getChildren().size() > 0) {
                                recurison(es.getChildren());
                            }
                        }
                    }
                }

                public List<EnergyStruc> pickTargetNode(List<EnergyStruc> lists) {
                    recurison(lists);
                    return callback;
                }

            }
            result = new Inner().pickTargetNode(energyStrucs);
        } else {
            return Collections.emptyList();
        }

        return result;
    }

}
